package com.lv.service.ui

import VideoHandle.EpEditor
import VideoHandle.EpVideo
import VideoHandle.OnEditorListener
import android.animation.ValueAnimator
import android.content.Intent
import android.graphics.SurfaceTexture
import android.media.MediaPlayer
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.text.Html
import android.text.Spanned
import android.view.*
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import android.widget.RelativeLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.SizeUtils
import com.lv.common.adapter.TrimVideoAdapter
import com.lv.common.base.BaseActivity
import com.lv.common.event.VideoEditInfo
import com.lv.common.utils.ARoutUtils
import com.lv.common.utils.MyUtils
import com.lv.common.utils.SaveImageUtils
import com.lv.common.utils.StatusBarUtil
import com.lv.common.utils.showToast
import com.lv.common.widget.video_editor.ExtractFrameWorkThread
import com.lv.common.widget.video_editor.ExtractVideoInfoUtil
import com.lv.common.widget.video_editor.RangeSeekBar
import com.lv.common.widget.video_editor.VideoThumbSpacingItemDecoration
import com.lv.service.R
import com.lv.service.databinding.ActivityEditorVideoCutBinding
import com.lv.service.model.ServiceViewModel
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import org.koin.androidx.viewmodel.ext.android.viewModel
import java.lang.ref.WeakReference
import java.math.BigDecimal


/**
 * 作者： ygx
 * 创建日期：2023/3/28 5:51 PM
 * 签名： 天行健，君子以自强不息；地势坤，君子以厚德载物。
 * -    _              _           _     _   ____  _             _ _
 * -   / \   _ __   __| |_ __ ___ (_) __| | / ___|| |_ _   _  __| (_) ___
 * -  / _ \ | '_ \ / _` | '__/ _ \| |/ _` | \___ \| __| | | |/ _` | |/ _ \
 * - / ___ \| | | | (_| | | | (_) | | (_| |  ___) | |_| |_| | (_| | | (_) |
 * -/_/   \_\_| |_|\__,_|_|  \___/|_|\__,_| |____/ \__|\__,_|\__,_|_|\___/
 * <p>
 * You never know what you can do until you try !
 * ----------------------------------------------------------------
 * 描述：视频编辑
 */
@Route(path = ARoutUtils.EditorVideoCutActivity)
class EditorVideoCutActivity : BaseActivity<ActivityEditorVideoCutBinding>(),
    View.OnClickListener {
    @Autowired(name = "mMediaUrl")
    @JvmField
    var mVideoPath: String = ""

    private var mMediaPlayer: MediaPlayer? = null

    // 最小剪辑时间3s
    private val MIN_CUT_DURATION = 3 * 1000L

    //视频最多剪切多长时间
    //    private static final long MAX_CUT_DURATION = 60 * 60 * 1000L;
    private val MAX_CUT_DURATION = 30 * 1000L

    //seekBar的区域内一共有多少张图片
    private val MAX_COUNT_RANGE = 10

    //左右两边间距
    private val MARGIN: Int = SizeUtils.dp2px(30.0f)

    //可裁剪区域的最大宽度
    private var mExtractVideoInfoUtil: ExtractVideoInfoUtil? = null
    private var mMaxWidth = 0
    private var videoEditAdapter: TrimVideoAdapter? = null
    private var seekBar: RangeSeekBar? = null

    //视频总时长
    private var duration: Long = 0

    //每毫秒所占的px
    private var averageMsPx = 0f

    //每px所占用的ms毫秒
    private var averagePxMs = 0f
    private var OutPutFileDirPath: String? = null

    //视频帧工具类
    private var mExtractFrameWorkThread: ExtractFrameWorkThread? = null
    private var isOverScaledTouchSlop = false

    //裁剪视频左边区域的时间位置, 右边时间位置
    private var leftProgress: Long = 0  //裁剪视频左边区域的时间位置, 右边时间位置
    private var rightProgress: Long = 0
    private var scrollPos: Long = 0
    private var mScaledTouchSlop = 0
    private var lastScrollX = 0

    //是否拖动中
    private var isSeeking = false

    private val viewModelService: ServiceViewModel by viewModel()
    private val myScope: CoroutineScope = CoroutineScope(SupervisorJob())

    override fun getLayoutRes() = R.layout.activity_editor_video_cut
    override fun initView() {
        super.initView()
        initStatusBar(this, true, false)
        ARouter.getInstance().inject(this)
        mBinding.apply {
            StatusBarUtil.setHeightAndPadding(this@EditorVideoCutActivity, viewSubToolbar)
            trimVideoCancel.setOnClickListener(this@EditorVideoCutActivity)
            trimVideoConfirm.setOnClickListener(this@EditorVideoCutActivity)
        }
    }


    override fun initConfig() {
        super.initConfig()
        SaveImageUtils.deleteAllInDir(this, "CameraCirPic")
        mExtractVideoInfoUtil = ExtractVideoInfoUtil(mVideoPath)
        mMaxWidth = ScreenUtils.getScreenWidth() - MARGIN * 2
        mScaledTouchSlop = ViewConfiguration.get(this).scaledTouchSlop

        mBinding.textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
                //                surfaceTexture = surface
                initMediaPlay(surface)
            }

            override fun onSurfaceTextureSizeChanged(
                surface: SurfaceTexture,
                width: Int,
                height: Int
            ) {
            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                return false
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
        }


        Observable.create<String> { e ->
            e.onNext(mExtractVideoInfoUtil?.getVideoLength() ?: "")
            e.onComplete()
        }
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Observer<String?> {
                override fun onSubscribe(d: Disposable) {
//                    subscribe(d)
                }

                override fun onNext(s: String) {
                    duration =
                        java.lang.Long.valueOf(mExtractVideoInfoUtil?.getVideoLength() ?: "0")
                    //矫正获取到的视频时长不是整数问题
                    val tempDuration = (duration / 1000f).toDouble()
                    duration = (BigDecimal(tempDuration).setScale(0, BigDecimal.ROUND_HALF_UP)
                        .toInt() * 1000).toLong()
                    LogUtils.e("视频总时长：$duration")
                    initEditVideo()
                }

                override fun onError(e: Throwable) {}
                override fun onComplete() {}
            })

    }

    private fun initRecyclerView() {
        mBinding.videoThumbListview.layoutManager =
            LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        videoEditAdapter = TrimVideoAdapter(this, mMaxWidth / 10)
        mBinding.videoThumbListview.adapter = videoEditAdapter
        mBinding.videoThumbListview.addOnScrollListener(mOnScrollListener)
    }

    private val mOnScrollListener: RecyclerView.OnScrollListener =
        object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                LogUtils.e("-------newState:>>>>>$newState")
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    isSeeking = false
                    videoStart()
                } else {
                    isSeeking = true
                    if (isOverScaledTouchSlop) {
                        videoPause()
                    }
                }
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                isSeeking = false
                val scrollX: Int = getScrollXDistance()
                //达不到滑动的距离
                if (Math.abs(lastScrollX - scrollX) < mScaledTouchSlop) {
                    isOverScaledTouchSlop = false
                    return
                }
                isOverScaledTouchSlop = true
                LogUtils.e("-------scrollX:>>>>>$scrollX")
                //初始状态,why ? 因为默认的时候有56dp的空白！
                if (scrollX == -MARGIN) {
                    scrollPos = 0
                } else {
                    // why 在这里处理一下,因为onScrollStateChanged早于onScrolled回调
                    videoPause()
                    isSeeking = true
                    scrollPos =
                        (averageMsPx * (MARGIN + scrollX)).toLong()
                    LogUtils.e("-------scrollPos:>>>>>$scrollPos")
                    leftProgress = seekBar!!.selectedMinValue + scrollPos
                    rightProgress = seekBar!!.selectedMaxValue + scrollPos
                    LogUtils.e("-------leftProgress:>>>>>$leftProgress")
                    mMediaPlayer?.seekTo(leftProgress.toInt())
                }
                lastScrollX = scrollX
            }
        }

    /**
     * 水平滑动了多少px
     *
     * @return int px
     */
    private fun getScrollXDistance(): Int {
        val layoutManager = mBinding.videoThumbListview.layoutManager as LinearLayoutManager
        val position = layoutManager.findFirstVisibleItemPosition()
        val firstVisibleChildView = layoutManager.findViewByPosition(position)
        val itemWidth = firstVisibleChildView!!.width
        return position * itemWidth - firstVisibleChildView.left
    }

    /**
     * 进度条拖动监听
     */
    private val mOnRangeSeekBarChangeListener: RangeSeekBar.OnRangeSeekBarChangeListener =
        RangeSeekBar.OnRangeSeekBarChangeListener { bar, minValue, maxValue, action, isMin, pressedThumb ->
            LogUtils.e("-----minValue----->>>>>>$minValue")
            LogUtils.e("-----maxValue----->>>>>>$maxValue")
            leftProgress = minValue + scrollPos
            rightProgress = maxValue + scrollPos
            LogUtils.e("-----leftProgress----->>>>>>$leftProgress")
            LogUtils.e("-----rightProgress----->>>>>>$rightProgress")
            when (action) {
                MotionEvent.ACTION_DOWN -> {
                    LogUtils.e("-----ACTION_DOWN---->>>>>>")
                    isSeeking = false
                    videoPause()
                }
                MotionEvent.ACTION_MOVE -> {
                    LogUtils.e("-----ACTION_MOVE---->>>>>>")
                    isSeeking = true
                    mMediaPlayer?.seekTo((if (pressedThumb === RangeSeekBar.Thumb.MIN) leftProgress else rightProgress).toInt())
                }
                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    LogUtils.e("-----ACTION_UP--leftProgress--->>>>>>$leftProgress")
                    isSeeking = false
                    //从minValue开始播
                    mMediaPlayer?.seekTo(leftProgress.toInt())
                    videoStart()
                    mBinding.videoShootTip.text =
                        getSelTimeTips((rightProgress - leftProgress) / 1000)
                }
                else -> {}
            }
        }

    private fun videoStart() {
        LogUtils.e("----videoStart----->>>>>>>")
        mMediaPlayer?.start()
        mBinding.positionIcon.clearAnimation()
        if (animator != null && animator?.isRunning == true) {
            animator?.cancel()
        }
        anim()
        handler.removeCallbacks(run)
        handler.post(run)
    }

    private fun videoProgressUpdate() {
        val currentPosition = mMediaPlayer?.currentPosition?.toLong() ?: 0
        LogUtils.e("----onProgressUpdate-cp---->>>>>>>$currentPosition")
        if (currentPosition >= rightProgress) {
            mMediaPlayer?.seekTo(leftProgress.toInt())
            mBinding.positionIcon.clearAnimation()
            if (animator != null && animator?.isRunning == true) {
                animator?.cancel()
            }
            anim()
        }
    }

    private fun videoPause() {
        isSeeking = false
        if (mMediaPlayer?.isPlaying == true) {
            mMediaPlayer?.pause()
            handler.removeCallbacks(run)
        }
        LogUtils.e("----videoPause----->>>>>>>")
        if (mBinding.positionIcon.visibility == View.VISIBLE) {
            mBinding.positionIcon.visibility = View.GONE
        }
        mBinding.positionIcon.clearAnimation()
        if (animator != null && animator?.isRunning == true) {
            animator?.cancel()
        }
    }

    private val handler = Handler()
    private val run: Runnable = object : Runnable {
        override fun run() {
            videoProgressUpdate()
            handler.postDelayed(this, 1000)
        }
    }

    override fun initData() {
        super.initData()

    }

    private fun initMediaPlay(surface: SurfaceTexture) {
        try {
            mMediaPlayer = MediaPlayer()
            mMediaPlayer?.setDataSource(mVideoPath)
            mMediaPlayer?.setSurface(Surface(surface))
            mMediaPlayer?.isLooping = true
            mMediaPlayer?.setOnPreparedListener(MediaPlayer.OnPreparedListener {
                mMediaPlayer?.start()
                updateTextureViewAspectRatio()
            })
            mMediaPlayer?.prepareAsync()

//            duration = (mPlayView?.duration ?: 0).toLong()
//            //矫正获取到的视频时长不是整数问题
//            val tempDuration = (duration / 1000f).toDouble()
//            duration = (BigDecimal(tempDuration).setScale(0, BigDecimal.ROUND_HALF_UP)
//                .toInt() * 1000).toLong()
//            initEditVideo()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun initEditVideo() {
        //for video edit
        val startPosition: Long = 0
        val endPosition = duration
        val thumbnailsCount: Int
        val rangeWidth: Int
        val isOver_10_s: Boolean
        if (endPosition <= MAX_CUT_DURATION) {
            isOver_10_s = false
            thumbnailsCount =
                MAX_COUNT_RANGE
            rangeWidth = mMaxWidth
        } else {
            isOver_10_s = true
            thumbnailsCount =
                (endPosition * 1.0f / (MAX_CUT_DURATION * 1.0f)
                        * MAX_COUNT_RANGE).toInt()
            rangeWidth =
                mMaxWidth / MAX_COUNT_RANGE * thumbnailsCount
        }
        mBinding.videoThumbListview.addItemDecoration(
            VideoThumbSpacingItemDecoration(
                MARGIN,
                thumbnailsCount
            )
        )
        //init seekBar
        if (isOver_10_s) {
            seekBar = RangeSeekBar(
                this,
                0L,
                MAX_CUT_DURATION
            )
            seekBar?.selectedMinValue = 0L
            seekBar?.selectedMaxValue = MAX_CUT_DURATION
        } else {
            seekBar = RangeSeekBar(this, 0L, endPosition)
            seekBar?.selectedMinValue = 0L
            seekBar?.selectedMaxValue = endPosition
        }
        seekBar?.setMin_cut_time(MIN_CUT_DURATION) //设置最小裁剪时间
        seekBar?.isNotifyWhileDragging = true
        seekBar?.setOnRangeSeekBarChangeListener(mOnRangeSeekBarChangeListener)
        mBinding.idSeekBarLayout.addView(seekBar)
        LogUtils.e("-------thumbnailsCount--->>>>$thumbnailsCount")
        averageMsPx = duration * 1.0f / rangeWidth * 1.0f
        LogUtils.e("-------rangeWidth--->>>>$rangeWidth")
        LogUtils.e("-------localMedia.getDuration()--->>>>$duration")
        LogUtils.e("-------averageMsPx--->>>>$averageMsPx")
//        OutPutFileDirPath = VideoUtil.getSaveEditThumbnailDir(this)
//        OutPutFileDirPath = MyUtils.getSDPath(this) + "files/Pictures/CameraCirPic"
        OutPutFileDirPath = "CameraCirPic"
        val extractW: Int =
            mMaxWidth / MAX_COUNT_RANGE
        val extractH: Int = SizeUtils.dp2px(34.0f)
        mExtractFrameWorkThread = ExtractFrameWorkThread(
            this,
            extractW, extractH, mUIHandler,
            mVideoPath,
            OutPutFileDirPath, startPosition, endPosition, thumbnailsCount
        )
        mExtractFrameWorkThread?.start()
        //init pos icon start
        leftProgress = 0
        rightProgress = if (isOver_10_s) {
            MAX_CUT_DURATION
        } else {
            endPosition
        }
        mBinding.videoShootTip.text = getSelTimeTips(rightProgress / 1000)
        averagePxMs = mMaxWidth * 1.0f / (rightProgress - leftProgress)
        LogUtils.e("------averagePxMs----:>>>>>$averagePxMs")
        initRecyclerView()
    }

    /**
     * 获取截取提示的文字
     */
    private fun getSelTimeTips(time: Long): Spanned? {
        val htmlStr = "已截取<font color = '#eb613d'>$time</font>秒的内容"
        return Html.fromHtml(htmlStr)
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.trim_video_cancel -> {
//                LiveEventBus.get(FindGoodsPicEvent::class.java)
//                    .post(FindGoodsPicEvent("", "1"))
                finish()
            }

            R.id.trim_video_confirm -> {
                trimmerAndCompressVideo()
            }

        }
    }


    override fun initEvents() {
        super.initEvents()
        rigestEventBus()
    }

    private fun rigestEventBus() {
//        LiveEventBus.get(VideoEditInfo::class.java).observe(this) { event ->
//            if (event == null) {
//                return@observe
//            }
//            val info: VideoEditInfo = event
//            videoEditAdapter?.addItemVideoInfo(info)
//        }
    }

    private fun updateTextureViewAspectRatio() {
        val videoWidth = mMediaPlayer?.videoWidth ?: 0
        val videoHeight = mMediaPlayer?.videoHeight ?: 0
        if (videoWidth > 0 && videoHeight > 0) {
            val videoAspectRatio = videoWidth.toFloat() / videoHeight.toFloat()
            val textureViewWidth = mBinding.textureView.width
//            val textureViewWidth = parentWidth
            val textureViewHeight = (textureViewWidth / videoAspectRatio).toInt()

            val layoutParams = mBinding.textureView.layoutParams as RelativeLayout.LayoutParams
            layoutParams.height = textureViewHeight
            mBinding.textureView.layoutParams = layoutParams
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        SaveImageUtils.deleteAllInDir(this, "CameraCirPic")
    }

    //视频处理相关----------------------------------------------------------------------------------
    //使用RxFFmpeg剪裁压缩视频处理方法V2----------------------------------------------------

    //视频处理相关----------------------------------------------------------------------------------
    //使用RxFFmpeg剪裁压缩视频处理方法V2----------------------------------------------------
    /**
     * 视频剪裁和压缩
     */
    private fun trimmerAndCompressVideo() {
        //暂停视频
        videoPause()
        startLoading()
//        NormalProgressDialog
//            .showLoading(this, resources.getString(R.string.in_process), false)
        LogUtils.e(
            "trimVideo...startSecond:" + leftProgress + ", endSecond:"
                    + rightProgress
        )
        val startProgress = leftProgress / 1000.0f
        val endProgress = rightProgress / 1000.0f
        val videoPath = mVideoPath
        val cutDuration = endProgress - startProgress
        trimmerAndCompressImpl(videoPath, startProgress, cutDuration)
    }

    //V2剪裁视频方法
    private fun trimmerAndCompressImpl(path: String?, startPos: Float, endPos: Float) {
        val epVideo = EpVideo(path)
        epVideo.clip(startPos, endPos)
        MyUtils.getSDPath(this)
//        val outPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath + "/CameraCir/" + "${System.currentTimeMillis()}.mp4"
        val outPath = MyUtils.getSDPath(this) + "${System.currentTimeMillis()}.mp4"

        EpEditor.exec(epVideo, EpEditor.OutputOption(outPath), object : OnEditorListener {
            override fun onSuccess() {
                runOnUiThread {
                    loadFinished()
                    cropFinish(outPath, endPos)
                }
            }

            override fun onFailure() {
                //剪裁视频失败
                runOnUiThread {
                    loadFinished()
                    showToast("编辑失败")
                }
            }

            override fun onProgress(v: Float) {
//                mProgressDialog.setProgress((v * 100).toInt())
            }
        })

    }

    //剪裁完成
    private fun cropFinish(path: String?, duration: Float) {
//        LiveEventBus.get(MediaSelectedEvent::class.java)
//            .post(MediaSelectedEvent(MediaSelectedEventEnum.VIDEO, path))
//        val finalPath = if (TextUtils.isEmpty(path)) "" else path!!
        val resultIntent = Intent()
        resultIntent.putExtra(
            "PARAMS_CROP_RESULT_PATH",
            path
        )
        resultIntent.putExtra("duration", duration)
        setResult(RESULT_OK, resultIntent)
        finish()
    }

    private var animator: ValueAnimator? = null

    private fun anim() {
        LogUtils.e("--anim--onProgressUpdate---->>>>>>>" + mMediaPlayer?.currentPosition)
        if (mBinding.positionIcon.visibility == View.GONE) {
            mBinding.positionIcon.visibility = View.VISIBLE
        }
        val params = mBinding.positionIcon
            .layoutParams as FrameLayout.LayoutParams
        val start: Int =
            (MARGIN + (leftProgress /*mVideoView.getCurrentPosition()*/ - scrollPos) * averagePxMs).toInt()
        val end: Int =
            (MARGIN + (rightProgress - scrollPos) * averagePxMs).toInt()
        animator = ValueAnimator
            .ofInt(start, end)
            .setDuration(
                rightProgress - scrollPos - (leftProgress /*mVideoView.getCurrentPosition()*/
                        - scrollPos)
            )
        animator?.interpolator = LinearInterpolator()
        animator?.addUpdateListener(ValueAnimator.AnimatorUpdateListener { animation ->
            params.leftMargin = animation.animatedValue as Int
            mBinding.positionIcon.layoutParams = params
        })
        animator?.start()
    }

    private val mUIHandler = MainHandler(this, Looper.myLooper()!!)

    class MainHandler(activity: EditorVideoCutActivity, looper: Looper) :
        Handler(looper) {
        private val mActivity: WeakReference<EditorVideoCutActivity>

        init {
            mActivity =
                WeakReference<EditorVideoCutActivity>(activity)
        }

        override fun handleMessage(msg: Message) {
            val activity: EditorVideoCutActivity? =
                mActivity.get()
            if (activity != null) {
                if (msg.what == ExtractFrameWorkThread.MSG_SAVE_SUCCESS) {
                    if (activity.videoEditAdapter != null) {
                        val info: VideoEditInfo = msg.obj as VideoEditInfo
                        activity.videoEditAdapter?.addItemVideoInfo(info)
                    }
                }
            }
        }
    }
}